/*
   Copyright 2012 Jason Drake (jadrake75@gmail.com)
 
   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at
 
       http://www.apache.org/licenses/LICENSE-2.0
 
   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.
 */
package org.javad.components;

import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Font;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;

import javax.swing.AbstractAction;
import javax.swing.GroupLayout;
import javax.swing.GroupLayout.Alignment;
import javax.swing.JButton;
import javax.swing.JDialog;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextPane;
import javax.swing.LayoutStyle.ComponentPlacement;
import javax.swing.SwingWorker;
import javax.swing.text.BadLocationException;

import org.bushe.swing.event.EventBus;
import org.bushe.swing.event.annotation.AnnotationProcessor;
import org.bushe.swing.event.annotation.EventSubscriber;
import org.javad.components.model.AboutDialogBean;

import pub.domain.GradientPanel;

@SuppressWarnings("serial")
public class AboutDialog extends JDialog {
	
	private JPanel mainPanel;
	private JPanel buttonPanel;
	private JButton btnOk;
	private JLabel labelIcon;
	private JPanel panel;
	private JScrollPane scrollPane;
	private JTextPane licenseText;
	private JLabel labelAppInfo;
	private GradientPanel contentPanel;
	private LinkLabel labelLink;
	
	private static Logger logger = Logger.getLogger(AboutDialog.class.getName());
	private static String LICENSE_INFO = null;
	
	private AboutDialogBean modelBean;
	
	
	
	public AboutDialog(AboutDialogBean bean) {
		AnnotationProcessor.process(this);
		setModelBean(bean);
		setTitle(bean.getTitle());
		initialize();
	}
	
	public void setModelBean(AboutDialogBean modelBean) {
		this.modelBean = modelBean;
	}
	
	public AboutDialogBean getModelBean() {
		return modelBean;
	}
	
	
	private void initialize() {
		setResizable(false);
		setModalExclusionType(ModalExclusionType.APPLICATION_EXCLUDE);
		setModal(true);
		setSize(640,400);
		getContentPane().setLayout(new GridLayout(0, 1, 0, 0));
		getContentPane().add(getContentPanel());
		getVersionAndLicenseInformation();
	}
	
	@EventSubscriber(eventClass=AboutEvent.class)
	public void onActionEvent(AboutEvent event) {
		if(event.getType() == EventType.LICENSE_INFO_PROCESSED) {
			List<String> info = event.getData();
			LICENSE_INFO = info.get(0);
			setLicenseInfo();
			String version = (info.size() > 1  && !info.get(1).isEmpty()) ? info.get(1) : ComponentResources.getString("message.unknown"); //$NON-NLS-1$
			getLabelAppInfo().setText(getBuildVersion(version));
		}
	}
	private void setLicenseInfo() {
		try {
			getLicenseText().setText("");
			getLicenseText().getStyledDocument().insertString(0, LICENSE_INFO, null);
			getLicenseText().setCaretPosition(0);
		} catch (BadLocationException e) {
			logger.log(Level.SEVERE,"Issue specifying the license text in the document.", e); 
		}
	}

	protected JPanel getMainPanel() {
		if (mainPanel == null) {
			mainPanel = new JPanel();
			mainPanel.setOpaque(false);
			GroupLayout gl_mainPanel = new GroupLayout(mainPanel);
			gl_mainPanel.setHorizontalGroup(
				gl_mainPanel.createParallelGroup(Alignment.LEADING)
					.addGroup(gl_mainPanel.createSequentialGroup()
						.addContainerGap()
						.addGroup(gl_mainPanel.createParallelGroup(Alignment.LEADING)
							.addComponent(getScrollPane(), GroupLayout.DEFAULT_SIZE, 464, Short.MAX_VALUE)
							.addGroup(gl_mainPanel.createSequentialGroup()
								.addComponent(getLabelIcon())
								.addPreferredGap(ComponentPlacement.RELATED)
								.addComponent(getPanel(), GroupLayout.DEFAULT_SIZE, 364, Short.MAX_VALUE)))
						.addContainerGap())
			);
			gl_mainPanel.setVerticalGroup(
				gl_mainPanel.createParallelGroup(Alignment.LEADING)
					.addGroup(gl_mainPanel.createSequentialGroup()
						.addContainerGap()
						.addGroup(gl_mainPanel.createParallelGroup(Alignment.LEADING)
							.addComponent(getLabelIcon())
							.addComponent(getPanel(), GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
						.addPreferredGap(ComponentPlacement.RELATED)
						.addComponent(getScrollPane(), GroupLayout.DEFAULT_SIZE, 179, Short.MAX_VALUE)
						.addContainerGap())
			);
			mainPanel.setLayout(gl_mainPanel);
		}
		return mainPanel;
	}
	protected JPanel getButtonPanel() {
		if (buttonPanel == null) {
			buttonPanel = new JPanel();
			buttonPanel.setPreferredSize(new Dimension(100, 40));
			buttonPanel.setOpaque(false);
			FlowLayout flowLayout = (FlowLayout) buttonPanel.getLayout();
			flowLayout.setAlignment(FlowLayout.RIGHT);
			buttonPanel.add(getBtnOk());
		}
		return buttonPanel;
	}
	protected JButton getBtnOk() {
		if (btnOk == null) {
			btnOk = new JButton(ComponentResources.getString("button.ok")); //$NON-NLS-1$
			btnOk.setPreferredSize(new Dimension(75, 23));
			btnOk.setName("btn-ok"); //$NON-NLS-1$
			btnOk.setAction(new CloseDialogAction());
		}
		return btnOk;
	}
	protected JLabel getLabelIcon() {
		if (labelIcon == null) {
			labelIcon = new JLabel("");
			labelIcon.setMinimumSize(new Dimension(96, 96));
			labelIcon.setIcon(getModelBean().getApplicationIcon()); //$NON-NLS-1$
			labelIcon.setPreferredSize(new Dimension(96, 96));
		}
		return labelIcon;
	}
	protected JPanel getPanel() {
		if (panel == null) {
			panel = new JPanel();
			panel.setOpaque(false);
			GroupLayout gl_panel = new GroupLayout(panel);
			gl_panel.setHorizontalGroup(
				gl_panel.createParallelGroup(Alignment.LEADING)
					.addComponent(getLabelLink(), GroupLayout.DEFAULT_SIZE, 364, Short.MAX_VALUE)
					.addComponent(getLabelAppInfo(), GroupLayout.DEFAULT_SIZE, 364, Short.MAX_VALUE)
			);
			gl_panel.setVerticalGroup(
				gl_panel.createParallelGroup(Alignment.LEADING)
					.addGroup(gl_panel.createSequentialGroup()
						.addComponent(getLabelAppInfo(), GroupLayout.PREFERRED_SIZE, 70, GroupLayout.PREFERRED_SIZE)
						.addPreferredGap(ComponentPlacement.RELATED)
						.addComponent(getLabelLink())
						.addContainerGap(GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
			);
			panel.setLayout(gl_panel);
		}
		return panel;
	}
	protected JScrollPane getScrollPane() {
		if (scrollPane == null) {
			scrollPane = new JScrollPane();
			scrollPane.setViewportView(getLicenseText());
		}
		return scrollPane;
	}
	protected JTextPane getLicenseText() {
		if (licenseText == null) {
			licenseText = new JTextPane();
			licenseText.setFont(new Font("Courier New", Font.PLAIN, 11));
			licenseText.setName("text-license");
			licenseText.setEditable(false);
		}
		return licenseText;
	}
	protected JLabel getLabelAppInfo() {
		if (labelAppInfo == null) {
			labelAppInfo = new JLabel();
			labelAppInfo.setText(getBuildVersion(ComponentResources.getString("message.unknown")));  //$NON-NLS-1$
		}
		return labelAppInfo;
	}
	
	private String getBuildVersion(String version) {
		String s = MessageFormat.format(getModelBean().getApplicationInfo(), version); //$NON-NLS-1$
		return UIHelper.convertToMultiline(s);
	}
	
	
	protected void getVersionAndLicenseInformation() {
		if( LICENSE_INFO == null ) {
			getLicenseText().setText(ComponentResources.getString("message.readingLicense"));
			(new LicenseAndVersionLoader()).execute();	
		} else {
			setLicenseInfo();
		}
		
	}
	
	protected JPanel getContentPanel() {
		if (contentPanel == null) {
			contentPanel = new GradientPanel();
			contentPanel.setBackground(UIHelper.Dark_Grey);
			contentPanel.setForeground(UIHelper.Medium_Grey);
			contentPanel.setDirection(GradientPanel.VERTICAL);
			GroupLayout gl_contentPanel = new GroupLayout(contentPanel);
			gl_contentPanel.setHorizontalGroup(
				gl_contentPanel.createParallelGroup(Alignment.TRAILING)
					.addComponent(getButtonPanel(), GroupLayout.DEFAULT_SIZE, 640, Short.MAX_VALUE)
					.addComponent(getMainPanel(), GroupLayout.DEFAULT_SIZE, 624, Short.MAX_VALUE)
			);
			gl_contentPanel.setVerticalGroup(
				gl_contentPanel.createParallelGroup(Alignment.TRAILING)
					.addGroup(gl_contentPanel.createSequentialGroup()
						.addComponent(getMainPanel(), GroupLayout.DEFAULT_SIZE, 353, Short.MAX_VALUE)
						.addPreferredGap(ComponentPlacement.RELATED)
						.addComponent(getButtonPanel(), GroupLayout.PREFERRED_SIZE, 41, GroupLayout.PREFERRED_SIZE))
			);
			contentPanel.setLayout(gl_contentPanel);
		}
		return contentPanel;
	}
	protected LinkLabel getLabelLink() {
		if (labelLink == null) {
			labelLink = new LinkLabel();
			labelLink.setName("aboutDialog-softwareLink"); //$NON-NLS-1$
			labelLink.setText(getModelBean().getApplicationLink()); //$NON-NLS-1$
		}
		return labelLink;
	}
	
	
	public class LicenseAndVersionLoader extends SwingWorker<Void, String> {

		private StringBuilder buf = new StringBuilder(4096);
		private StringBuilder build = new StringBuilder(512);
		
		public LicenseAndVersionLoader() {
		}
		
		@Override
		protected Void doInBackground() throws Exception {
			readFile(buf, "/VERSION.txt");
			readFile(buf, "/NOTICE.txt");
			readFile(build, "/buildInfo.txt");
			return null;
		}
		
		private void readFile(StringBuilder buf, String resource) {
			try {
			    BufferedReader in = new BufferedReader(new InputStreamReader(getClass().getResourceAsStream(resource)));
			    String str;
			    while ((str = in.readLine()) != null) {
			    	if( buf.length() > 0 ) {
			    		buf.append('\n');
			    	}
			        buf.append(str);
			    }
			    in.close();
			} catch (IOException e) {
				logger.log(Level.SEVERE,"Unexpected error reading " + resource, e);
			}
		}

		@Override
		protected void done() {
			List<String> info = new ArrayList<String>();
			info.add(buf.toString());
			info.add(build.toString());
			AboutEvent event = new AboutEvent(EventType.LICENSE_INFO_PROCESSED, info);
			EventBus.publish(event);
		}
	}
	
	private class CloseDialogAction extends AbstractAction {
		public CloseDialogAction() {
			putValue(NAME, ComponentResources.getString("button.ok"));
		}
		
		public void actionPerformed(ActionEvent e) {
			dispose();
		}
	}
	
	
	public class AboutEvent {

		private EventType type;
		private Object data;
		private Object source;
		
		public AboutEvent(EventType type) {
			super();
			this.type = type;
		}
		
		public AboutEvent(EventType type, Object data) {
			this(type);
			this.data = data;
		}
		
		public AboutEvent(EventType type, Object data, Object source) {
			this(type,data);
			setSource(source);
		}
		
		public void setSource(Object source) {
			this.source = source;
		}
		
		public EventType getType() {
			return type;
		}
		
		@SuppressWarnings("unchecked")
		public <X> X getSource() {
			return (X)source;
		}
		
		@SuppressWarnings("unchecked")
		public <X> X getData() {
			return (X)data;
		}
	}
	
	public enum EventType {
		LICENSE_INFO_PROCESSED,
		
	}
}
